table of contents
SELECT(2) | Podręcznik programisty Linuksa | SELECT(2) |
NAZWA¶
select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchroniczne zwielokratnianie we/wy
SKŁADNIA¶
/* Zgodnie z POSIX 1003.1-2001 */
#include <sys/select.h>
/* Zgodnie z wcześniejszymi standardami */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);
FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);
OPIS¶
Funkcje select i pselect oczekują na zmianę statusu pewnej liczby deskryptorów plików.
Ich funkcjonalność jest identyczna, jeśli pominąć trzy różnice:
- (i)
- Funkcja select używa czasu parametru timeout, który jest typu struct timeval (z sekundami i mikrosekundami), podczas gdy pselect używa typu struct timespec (z sekundami i nanosekundami).
- (ii)
- Funkcja select może aktualizować parametr timeout, aby wskazać jak dużo czasu minęło. Funkcja pselect nie zmienia tego parametru.
- (iii)
- Funkcja select nie posiada parametru sigmask i zachowuje się jak pselect wywołane z NULL sigmask.
Podglądane są trzy niezależne zestawy deskryptorów. Te, które są wymienione w readfds będą obserwowane w celu dowiedzenia się, czy nie ma tam jakichś znaków dostępnych do czytania (dokładniej, aby dowiedzieć się, czy read nie spowoduje zablokowania, desktyptor pliku jest również przygotowany na koniec pliku). Deskryptory wymienione w writefds będą obserwowane w celu dowiedzenia się, czy zapis nie spowoduje blokady, a deskryptory wymienione w exceptfds będą obserwowane w celu dowiedzenia się, czy nie ma na nich wyjątku. Przy wyjściu, zbiory te są modyfikowane, wskazując, które z deskryptorów zmieniły status.
Do obsługi tych zbiorów udostępnone są cztery makra: FD_ZERO czyści zbiór. FD_SET i FD_CLR dodają, lub usuwają ze zbioru podany deskryptor. FD_ISSET sprawdza, czy deskryptor jest częścią zbioru. Jest to przydatne po zakończeniu select.
n jest nawyższym numerem deskryptora z wszystkich trzech zbiorów plus 1.
timeout jest górną granicą czasu, który upynie przed zakończeniem działania funkcji select. Gdy przyjmie wartość zero, select zakończy pracę natychmiast. (Jest to przydatne w uwspólnianiu.) Jeśli timeout jest równe NULL (brak czasu przeterminowania), select może blokować w nieskończoność.
sigmask jest wskaźnikiem do ksli sygnałów (zobacz sigprocmask(2)). Jeśli nie jest równe NULL, to pselect najpierw zastępuje bieżącą maskę sygnałów maską wskazywaną przez sigmask, a następnie wywołuje funkcję `select' i ponownie odtwarza originalną maskę sygnałów.
Idea pselect polega na tym, że gdy chce się oczekiwać na zdarzenie będące sygnałem lub czymś na deskryptorze pliku, potrzebny jest atomowy test zapobiegający sytuacjom wyścigu. (Przypuśćmy, że procedura obsługi sygnału ustawia globalny znacznik i kończy działanie. Wówczas, test tego znacznika globalnego, po którym następuje wywołanie select() może wisieć w nieskończoność, gdyby sygnał przybył natychmiast po teście, ale przed wywołaniem. Inaczej mówiąc, pselect zezwala na, najpierw, zablokowanie sygnałów, następnie obsłużenie dostarczonych sygnałów, aby wreszcie wywołać pselect() z pożądanym sigmask, unikając wyścigu.) Ponieważ obecnie Linux nie posiada funkcji systemowej pselect(), aktualna procedura w glibc2 wciąż zawiera ryzyko takiego wyścigu.
Przeterminowanie¶
Struktury czasu, których to dotyczy, są zdefiniowane w <sys/time.h> i wyglądają następująco
struct timeval {
long tv_sec; /* sekundy */
long tv_usec; /* mikrosekundy */ };
i
struct timespec {
long tv_sec; /* sekundy */
long tv_nsec; /* nanosekundy */ };
(Jednakże odnośnie wersji POSIX 1003.1-2001 zobacz poniżej.)
Niektóre programy wywołują select z wszystkimi trzema zbiorami pustymi, z n równym zeru i niezerowym timeout. Jest to całkiem przenośny sposób pauzowania z dokładnością subsekundową.
Pod Linuksem funkcja select modyfikuje timeout, aby odzwierciedlić ilość nieprzespanego czasu; większość innych implementacji tego nie robi. Powoduje to problemy, zarówno gdy kod linuksowy odczytujący timeout zostanie przeniesiony na inne systemy operacyjne, jak i gdy kod przeniesiony pod Linuksa z innych systemów używa ponownie struct timeval dla wielu selectów w pętli, bez reinicjalizacji. Należy traktować timeout jako niezdefiniowany po zakończeniu select.
WARTOŚĆ ZWRACANA¶
Po pomyślnym zakończeniu, select i pselect zwracają liczbę deskryptorów w zbiorach deskryptorów. Może ona być zerowa, jeśli nastąpi przeterminowanie nim coś ciekawego się zdarzy. Po błędzie, zwracane jest -1 i odpowiednio ustawiane errno; zbiory deskryptorów i timeout stają się niezdefiniowane, więc nie należy polegać na ich zawartości.
BŁĘDY¶
PRZYKŁAD¶
#include <stdio.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int main(void) {
fd_set rfds;
struct timeval tv;
int retval;
/* Obserwacja stdin (fd 0) i sprawdzanie kiedy ma wejście. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Czekanie nie dłużej niż sekund. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
/* Nie należy już polegać na wartości tv! */
if (retval)
printf("Dane są już dostępne.\n");
/* FD_ISSET(0, &rfds) będzie prawdziwy. */
else
printf("Brak danych w ciągu 5 sekund.\n");
exit(0); }
ZGODNE Z¶
4.4BSD (funkcja select pojawiła się pierwotnie w 4.2BSD). W ogólności przenośne do/z systemów nie-BSD wspierających sklonowaną warstwę gniazd BSD (włączając warianty Systemu V). Jednakże, należy zauważyć, że warianty Systemu V zasadniczo ustawiają zmienną timeout przed zakończeniem, ale wariant BSD tego nie robi.
Funkcja pselect jest zdefiniowana w IEEE Std 1003.1g-2000 (POSIX.1g) oraz częściowo w POSIX 1003.1-2001. Można ją znaleźć w glibc2.1 i późniejszych. Glibc2.0 zawiera funkcję o tej samej nazwie, która jednakże, nie posiada parametru sigmask.
UWAGI¶
fd_set jest buforem o stałym rozmiarze. Wykonanie FD_CLR lub FD_SET z ujemną wartością fd albo z wartością większą lub równą FD_SETSIZE spowoduje zachowanie niezdefiniowane. Ponadto POSIX wybaga, by fd był prawidłowym deskryptorem pliku.
Odnośnie używanych typów, klasyczna sytuacja polega na tym, że oba pola struktury struct timeval są typu long (jak pokazano powyżej), a sama struktura jest zdefiniowana w <sys/time.h>. W POSIX 1003.1-2001 sytuacja jest następująca
struct timeval {
time_t tv_sec; /* sekundy */
suseconds_t tv_usec; /* mikrosekundy */ };
przy czym struktura jest zdefiniowana w <sys/select.h> a typy time_t i suseconds_t zdefiniowano w <sys/types.h>.
Odnośnie prototypów, klasyczna sytuacja polega na tym, że dla select należy włączyć <time.h>. Sytuacja z POSIX 1003.1-2001 polega na tym, że dla select i pselect należy włączyć <sys/select.h>. libc4 i libc5 nie zawierają pliku nagłówkowego <sys/select.h>; w glibc 2.0 i późniejszymi ten plik nagłówkowy istnieje. W glibc 2.0 udostępnia on bezwarunkowo błędny prototyp dla pselect. W glibc 2.1-2.2.1 udostępnia on pselect, gdy zdefiniowane jest _GNU_SOURCE. W glibc 2.2.2-2.2.4 udostępnia go natomiast, gdy zdefiniowane jest _XOPEN_SOURCE i ma wartość 600 lub większą. Niewątpliwie, począwszy od POSIX 1003.1-2001 plik ten powinien udostępniać prototyp standardowo.
ZOBACZ TAKŻE¶
Samouczek z dyskusją i przykładami znajduje się w select_tut(2).
Rzeczy w nieokreślony sposób powiązane z tym można znaleźć w accept(2), connect(2), poll(2), read(2), recv(2), send(2), sigprocmask(2), write(2)
2001-02-09 | Linux 2.4 |